package texture;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class StitcherDynamic extends Stitcher{
	public StitcherDynamic(int maxWidth, int maxHeight, boolean forcePowerOf2) {
		this(maxWidth, maxHeight, forcePowerOf2, 0);
	}

	public StitcherDynamic(int maxWidth, int maxHeight, boolean forcePowerOf2, int maxTileDimension) {
		super(maxWidth, maxHeight, forcePowerOf2,maxTileDimension);		
	}	

	public void doStitch() {
		StitchHolder[] astitchholder = (StitchHolder[]) this.setStitchHolders.toArray(new StitchHolder[this.setStitchHolders.size()]);
		Arrays.sort(astitchholder);
		StitchHolder[] astitchholder1 = astitchholder;
		int i = astitchholder.length;

		for (int j = 0; j < i; ++j) {
			StitchHolder stitchholder = astitchholder1[j];

			if (!this.allocateSlot(stitchholder)) {
				String msgTemplate ="Unable to fit: %s - size: %dx%d - Maybe try a lowerresolution texturepack?";
				String iconName =stitchholder.getAtlasSprite().getIconName();
				Integer iconWidth = Integer.valueOf(stitchholder.getAtlasSprite().getIconWidth());
				Integer iconHeight =Integer.valueOf(stitchholder.getAtlasSprite().getIconHeight());
				String s = String.format(msgTemplate, new Object[] { iconName, iconWidth, iconHeight });
				throw new StitcherException(stitchholder, s);
			}
		}

		if (this.forcePowerOf2) {
			this.currentWidth = this.getCeilPowerOf2(this.currentWidth);
			this.currentHeight = this.getCeilPowerOf2(this.currentHeight);
		}
	}

	private boolean allocateSlot(StitchHolder stitchHolder) {
		for (int i = 0; i < this.stitchSlots.size(); ++i) {
			if ((this.stitchSlots.get(i)).addSlot(stitchHolder)) {
				return true;
			}

			stitchHolder.rotate();

			if (((StitchSlot) this.stitchSlots.get(i)).addSlot(stitchHolder)) {
				return true;
			}

			stitchHolder.rotate();
		}

		return this.expandAndAllocateSlot(stitchHolder);
	}

	private boolean expandAndAllocateSlot(StitchHolder stitchHolder) {
        int i = Math.min(stitchHolder.getHeight(), stitchHolder.getWidth());
        boolean flag = this.currentWidth == 0 && this.currentHeight == 0;
        boolean flag1;
        
		if (this.forcePowerOf2) {
			int j = this.getCeilPowerOf2(this.currentWidth);
			int k = this.getCeilPowerOf2(this.currentHeight);
			
			int l = this.getCeilPowerOf2(this.currentWidth + i);
			int i1 = this.getCeilPowerOf2(this.currentHeight + i);
			
			boolean flag2 = l <= this.maxWidth;
			boolean flag3 = i1 <= this.maxHeight;

			if (!flag2 && !flag3) {//not expandable
				return false;
			}

			int j1 = Math.max(stitchHolder.getHeight(), stitchHolder.getWidth());

			if (flag && !flag2 && this.getCeilPowerOf2(this.currentHeight + j1) > this.maxHeight) {
				return false;
			}

			boolean flag4 = j != l;
			boolean flag5 = k != i1;

			if (flag4 ^ flag5) {
				flag1 = flag5 && flag3; // Forge: Bug fix: Attempt to fill all downward space before expanding width
			} else {
				flag1 = flag2 && j <= k;
			}
		} else {
			boolean flag6 = this.currentWidth + i <= this.maxWidth;
			boolean flag7 = this.currentHeight + i <= this.maxHeight;

			if (!flag6 && !flag7) {
				return false;
			}

			flag1 = (flag || this.currentWidth <= this.currentHeight) && flag6;
		}

		StitchSlot stitchslot;

        if (flag1)
        {
            if (stitchHolder.getWidth() > stitchHolder.getHeight())
            {
                stitchHolder.rotate();
            }

            if (this.currentHeight == 0)
            {
                this.currentHeight = stitchHolder.getHeight();
            }

            stitchslot = new StitchSlot(this.currentWidth, 0, stitchHolder.getWidth(), this.currentHeight);
            this.currentWidth += stitchHolder.getWidth();
        }
        else
        {
            stitchslot = new StitchSlot(0, this.currentHeight, this.currentWidth, stitchHolder.getHeight());
            this.currentHeight += stitchHolder.getHeight();
        }

        stitchslot.addSlot(stitchHolder);
        this.stitchSlots.add(stitchslot);
        return true;
	}

	private int getCeilPowerOf2(int par1) {
		int j = par1 - 1;
		j |= j >> 1;
		j |= j >> 2;
		j |= j >> 4;
		j |= j >> 8;
		j |= j >> 16;
		return j + 1;
	}

	public List<TextureAtlasSprite> getStichSlots() {
        ArrayList<StitchSlot> arraylist = new ArrayList<>();
        Iterator<StitchSlot> iterator = this.stitchSlots.iterator();

        while (iterator.hasNext())
        {
            StitchSlot stitchslot = iterator.next();
            stitchslot.getAllStitchSlots(arraylist);
        }

        ArrayList<TextureAtlasSprite> arraylist1 = new ArrayList<>();
        Iterator<StitchSlot> iterator1 = arraylist.iterator();

        while (iterator1.hasNext())
        {
            StitchSlot stitchslot1 = iterator1.next();
            StitchHolder stitchholder = stitchslot1.getStitchHolder();
            
            TextureAtlasSprite textureatlassprite = stitchholder.getAtlasSprite();
            textureatlassprite.initSprite(this.currentWidth, this.currentHeight, stitchslot1.getOriginX(), stitchslot1.getOriginY(), stitchholder.isRotated());
            arraylist1.add(textureatlassprite);
        }

        return arraylist1;
	}
}

